package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.sys.modules.models.SysCurrency;
import cn.wizzer.app.sys.modules.services.SysCurrencyService;
import cn.wizzer.app.user.modules.models.UserAccount;
import cn.wizzer.app.user.modules.models.enums.UserColEnum;
import cn.wizzer.app.user.modules.models.vo.UserAccountVo;
import cn.wizzer.app.user.modules.models.vo.WalletVO;
import cn.wizzer.app.user.modules.services.account.UserAccountService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserAccountService.class)
public class UserAccountServiceImpl extends BaseServiceImpl<UserAccount> implements UserAccountService {

    public UserAccountServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;

    @Inject
    @Reference
    private SysCurrencyService currencyService;


    @Override
    public UserAccount select(String userId, String currencyId) {
        UserAccount userAccount = this.fetch(Cnd.where("userId", "=", userId)
                .and("currencyId", "=", currencyId));
        if (null == userAccount) {
            userAccount = new UserAccount();
            userAccount.setBalance(BigDecimal.ZERO);
            userAccount.setCtAt(System.currentTimeMillis());
            userAccount.setUserId(userId);
            userAccount.setCurrencyId(currencyId);
            this.insert(userAccount);
        }
        return userAccount;
    }

    @Override
    public Pagination listPage(String conditionData, String currencyId, String searchKeyword, Integer pageNumber, Integer pageSize, String pageOrderName, String pageOrderBy) {
        // 子句查询计算总额
        Sql sql = Sqls.create("SELECT a.userId,a.balance,a.opAt,c.name AS currencyName,u.userName,u.nickName,")
                .appendSourceSql("(SELECT SUM(ROUND(ua.balance * sc.rate, 2)) FROM user_account AS ua")
                .appendSourceSql("LEFT JOIN sys_currency AS sc ON ua.currencyId = sc.id")
                .appendSourceSql("LEFT JOIN user AS us on ua.userId = us.id")
                .appendSourceSql("WHERE userId = a.userId ) as totalBalance")
                .appendSourceSql("FROM user_account AS a");
        Sql joinSql = Sqls.create("LEFT JOIN user AS u ON u.id = a.userId " +
                "LEFT JOIN sys_currency AS c ON c.id = a.currencyId" +
                "$condition ");
        Cnd cnd = Cnd.NEW();
        if (Strings.isNotBlank(conditionData)) {
            String[] split = conditionData.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    cnd.and("u." + colName, "=", "0");
                }
            }
        }
        if (Strings.isNotBlank(searchKeyword)) {
            cnd.and(Cnd.exps("u.userName", "=", searchKeyword)
                    .or("u.nickName", "=", searchKeyword)
                    .or("u.email", "=", searchKeyword));
        }
        if (Strings.isNotBlank(currencyId)) {
            cnd.and("a.currencyId", "=", currencyId);
        }
        // 按金额排序
        cnd.groupBy("a.userId", "a.balance", "a.opAt", "c.name", "u.userName", "u.nickName");
        cnd.orderBy(pageOrderName, pageOrderBy);
        joinSql.setCondition(cnd);
        sql.appendSourceSql(joinSql.toString());
        return dbService.listPage(UserAccountVo.class, pageNumber, pageSize, sql.toString());
    }

    @Override
    public BigDecimal searchSum(String conditionData, String currencyId, String searchKeyword) {
        StringBuffer sb = new StringBuffer();
        sb.append("select IFNULL(sum(ua.balance * sc.rate), 0)");
        sb.append(" from user_account ua");
        sb.append(" left join sys_currency sc on ua.currencyId = sc.id");
        sb.append(" left join user u on u.id = ua.userId");
        sb.append(" where 1=1");
        if (Strings.isNotBlank(conditionData)) {
            String[] split = conditionData.split(",");
            for (String col : split) {
                String colName = UserColEnum.getValByName(col);
                if (Strings.isNotBlank(colName)) {
                    // 默认不显示游客、内部账号
                    sb.append(" and u.").append(colName).append(" = 0");
                }
            }
        }
        if (Strings.isNotBlank(searchKeyword)) {
            sb.append(" and ( u.nickName = '").append(searchKeyword).append("'");
            sb.append(" or u.email = '").append(searchKeyword).append("'");
            sb.append(" or u.userName = '").append(searchKeyword).append("' )");
        }
        if (Strings.isNotBlank(currencyId)) {
            sb.append(" and ua.currencyId = '").append(currencyId).append("'");
        }
        Sql sql = Sqls.create(sb.toString());
        sql.setCallback(Sqls.callback.str());
        this.dao().execute(sql);
        return new BigDecimal(sql.getString()).setScale(6, BigDecimal.ROUND_DOWN);
    }


    /**
     * 计算用户账户的总额
     *
     * @param appid
     */
    @Override
    public BigDecimal calTotalBalance(String appid) {
        BigDecimal amount = BigDecimal.ZERO;
        // 获取用户钱包各币种金额及汇率
        List<WalletVO> wallets = this.wallets(appid);
        if (wallets.size() > 0) {
            amount = wallets.stream()
                    .map(walletVO -> walletVO.getAmount().multiply(walletVO.getRate()))
                    .reduce(BigDecimal::add).get();
        }
        return amount.setScale(2, RoundingMode.HALF_UP);
    }

    @Override
    public List<WalletVO> wallets(String appid) {
        List<SysCurrency> allCurrency = currencyService.getAll();
        return allCurrency.stream()
                .map(currency -> WalletVO.create(currency, this.select(appid, currency.getId()).getBalance()))
                .collect(Collectors.toList());
    }
}
